//
// Created by haoba on 2018/4/1.
//
#include "../include/recordio.h"
#include <iostream>

using namespace std;

int32_t negone = -1;

struct serializeBuff *create_serialize_buff(void){
    struct serializeBuff * buff;
    buff = (serializeBuff*)malloc(sizeof(struct serializeBuff));
    if (!buff) {
        return 0;
    }
    buff->off = 0;
    buff->buff = (char*)malloc(128);
    buff->len = 128;
    return buff;
}

struct serializeBuff *create_serialize_buff(char * buff,int32_t len){
    struct serializeBuff * sbuff;
    sbuff = (serializeBuff*)malloc(sizeof(struct serializeBuff));
    if (!buff) {
        return 0;
    }
    sbuff->off = 0;
    sbuff->buff = buff;
    sbuff->len = len;
    return sbuff;
}
void close_serialize_buff(struct serializeBuff *buff){
    free(buff->buff);
    free(buff);
}

void Edeallocate_String(char **s)
{
    if (*s)
        free(*s);
    *s = 0;
}

void Edeallocate_Buffer(struct buffer *b)
{
    if (b->buff)
        free(b->buff);
    b->buff = 0;
}

struct buff_struct {
    int32_t len;
    int32_t off;
    char *buffer;
};

static int Eresize_buffer(struct serializeBuff *s, int newlen)
{
    cout<<"resize buffer"<<endl;
    char *buffer= NULL;
    while (s->len < newlen) {
        s->len *= 2;
    }
    buffer = (char*)realloc(s->buff, s->len);
    if (!buffer) {
        s->buff = 0;
        return -ENOMEM;
    }
    s->buff = buffer;
    return 0;
}

int64_t Ezoo_htonll(int64_t v)
{
    int i = 0;
    char *s = (char *)&v;
    if (htonl(1) == 1) {
        return v;
    }
    for (i = 0; i < 4; i++) {
        int tmp = s[i];
        s[i] = s[8-i-1];
        s[8-i-1] = tmp;
    }

    return v;
}

int Eserialize_Int(struct serializeBuff * buff,int32_t * d){
    int32_t i = htonl(*d);
    if ((buff->len - buff->off) < sizeof(i)) {
        int rc = Eresize_buffer(buff, buff->len + sizeof(i));
        if (rc < 0) return rc;
    }
    memcpy(buff->buff+buff->off, &i, sizeof(i));
    buff->off+=sizeof(i);
    return 0;
}
int Eserialize_Long(struct serializeBuff * buff,int64_t * d){
    int64_t i = Ezoo_htonll(*d);
    if ((buff->len - buff->off) < sizeof(i)) {
        int rc = Eresize_buffer(buff, buff->len + sizeof(i));
        if (rc < 0) return rc;
    }
    memcpy(buff->buff+buff->off, &i, sizeof(i));
    buff->off+=sizeof(i);
    return 0;
}
int Eserialize_Bool(struct serializeBuff * buff,bool * d){
    if ((buff->len - buff->off) < 1) {
        int rc = Eresize_buffer(buff, buff->len + 1);
        if (rc < 0)
            return rc;
    }
    buff->buff[buff->off] = (*d == 0 ? '\0' : '\1');
    buff->off++;
    return 0;
}
int Eserialize_CString(struct serializeBuff * buff,int32_t len,char ** d){
    int rc;
    if (!(*d)) {
        Eserialize_Int(buff,&negone);
        return 0;
    }
    rc = Eserialize_Int(buff, &len);
    if (rc < 0)
        return rc;
    if ((buff->len - buff->off) < len) {
        rc = Eresize_buffer(buff, buff->len + len);
        if (rc < 0)
            return rc;
    }
    memcpy(buff->buff+buff->off, *d, len);
    buff->off += len;
    return 0;
}
int Eserialize_String(struct serializeBuff * buff,string & d){
    int rc;
    int32_t len = d.size();
    if (len==0) {
        Eserialize_Int(buff,&len);
        return 0;
    }
    rc = Eserialize_Int(buff, &len);
    if (rc < 0)
        return rc;
    if ((buff->len - buff->off) < len) {
        rc = Eresize_buffer(buff, buff->len + len);
        if (rc < 0)
            return rc;
    }
    memcpy(buff->buff+buff->off, d.c_str(), len);
    buff->off += len;
    return 0;
}
int Edeserialize_Int(struct serializeBuff * buff,int32_t  * d){
    if ((buff->len - buff->off) < sizeof(*d)) {
        return -E2BIG;
    }
    memcpy(d, buff->buff+buff->off, sizeof(*d));
    buff->off+=sizeof(*d);
    *d = ntohl(*d);
    return 0;
}
int Edeserialize_Long(struct serializeBuff * buff,int64_t  * d){
    int64_t v = 0;
    if ((buff->len - buff->off) < sizeof(*buff)) {
        return -E2BIG;
    }
    memcpy(d, buff->buff+buff->off, sizeof(*d));
    buff->off+=sizeof(*d);
    v = Ezoo_htonll(*d); // htonll and  ntohll do the same
    *d = v;
    return 0;
}
int Edeserialize_Bool(struct serializeBuff * buff,bool  * d){
    if ((buff->len - buff->off) < 1) {
        return -E2BIG;
    }
    *d = buff->buff[buff->off];
    buff->off+=1;
    return 0;
}
int Edeserialize_String(struct serializeBuff * buff,string & d){
    int32_t len = 0;
    int rc = Edeserialize_Int(buff,&len);
    if (rc < 0)
        return rc;
    if ((buff->len - buff->off) < len) {
        return -E2BIG;
    }
    if (len < 0) {
        printf("deserialize string fail len=%d",len);
        return -EINVAL;
    }
    d.append(buff->buff+buff->off,len);
    buff->off += len;
    return 0;
}
int Edeserialize_CString(struct serializeBuff * buff,char ** d){
    int32_t len = 0;
    int rc = Edeserialize_Int(buff,&len);
    if (rc < 0)
        return rc;
    if ((buff->len - buff->off) < len) {
        return -E2BIG;
    }
    if (len < 0) {
        printf("deserialize cstring fail len=%d",len);
        return -EINVAL;
    }
    *d = (char *)malloc(len+1);
    if (!d) {
        return -ENOMEM;
    }
    memcpy(*d, buff->buff+buff->off, len);
    (*d)[len] = '\0';
    buff->off += len;
    return 0;
}



